
#include "SSB_sys_def.h"
#include "SSB_system.h"
#include "SSB_socket.h"
#include "SSB_AT.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"

#include "esp_log.h"
#include "esp_wifi.h"
#include "esp_event_loop.h"
#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include "lwip/netdb.h"
#include "lwip/dns.h"

extern char socket_server[];
extern unsigned int socket_port;
extern char http_domain[];
extern int socket_connected;

int SSB_sockfd = -1;
int socket_not_received_count = 0;
SSB_Socket_callback_fun ssb_socket_cb = NULL;
SSB_on_socket_status_change_hand ssb_socket_status_change_cb = NULL;

void SSB_socket_free()
{
    if (SSB_sockfd >= 0)
    {
        close(SSB_sockfd);
        SSB_sockfd = -1;
    }
    socket_connected = 0;
    if (ssb_socket_status_change_cb != NULL)
    {
        ssb_socket_status_change_cb(0);
    }
}

static void socket_connect()
{
    int ret;
    struct sockaddr_in sock_addr;
    struct hostent *hp;
    struct ip4_addr *ip4_addr;
    //ESP_LOGI(SSB_TAG, "pppppppppppppppppppppppppppp");
    SSB_socket_free();
    ESP_LOGI(SSB_TAG, "get %s IP address", socket_server);
    hp = gethostbyname(socket_server);
    if (!hp)
    {
        ESP_LOGI(SSB_TAG, "DNS failed");
        goto failed1;
    }
    ip4_addr = (struct ip4_addr *)hp->h_addr;
    ESP_LOGI(SSB_TAG, IPSTR, IP2STR(ip4_addr));
    ESP_LOGI(SSB_TAG, "create socket ......");
    SSB_sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
    if (SSB_sockfd < 0)
    {
        ESP_LOGI(SSB_TAG, "Create socket failed");
        goto failed1;
    }
    ESP_LOGI(SSB_TAG, "OK");

    ESP_LOGI(SSB_TAG, "socket connect to remote %s ......", socket_server);
    memset(&sock_addr, 0, sizeof(sock_addr));
    sock_addr.sin_family = AF_INET;
    sock_addr.sin_addr.s_addr = ip4_addr->addr;
    sock_addr.sin_port = htons(socket_port);
    ret = connect(SSB_sockfd, (struct sockaddr *)&sock_addr, sizeof(sock_addr));
    if (ret)
    {
        ESP_LOGI(SSB_TAG, "Socket connect failed");
        goto failed3;
    }
    ESP_LOGI(SSB_TAG, "OK");

    // ESP_LOGI(TAG, "OK");
    socket_connected = 1;
    if (ssb_socket_status_change_cb != NULL)
    {
        ssb_socket_status_change_cb(1);
    }
    return;
// failed5:
//     SSL_shutdown(ssl);
failed3:
    close(SSB_sockfd);
    SSB_sockfd = -1;
failed1:
    return;
}

int SSB_socket_write(char *d, int len)
{
    if (SSB_sockfd < 0)
    {
        return -1;
    }
    if (!socket_connected)
    {
        return -1;
    }
    int ret = 0;
    ret = send(SSB_sockfd, d, len, 0);
    return ret;
}

void SSB_socket_hearbeat_task()
{
    extern int SSB_net_initialized;
    int hbt = 0;
    while (1)
    {
        vTaskDelay(1000 / portTICK_PERIOD_MS);
        if (!SSB_net_initialized)
        {
            continue;
        }

        if (!socket_connected)
        {
            socket_connect();
        }

        if (!socket_connected)
        {
            continue;
        }
        hbt = hbt + 1;
        if (hbt >= 10)
        {
            if (SSB_socket_write("hi\r\n", strlen("hi\r\n")))
            {
                //socket_not_received_count = socket_not_received_count + 1;
            }
            hbt = 0;
        }
        if (socket_not_received_count >= 3)
        {
            ESP_LOGI(SSB_TAG, "Socket is dead.");
            socket_not_received_count = 0;
            SSB_socket_free();
        }
        //hb\n
        //vTaskDelete(NULL);
    }
}

void SSB_socket_read_task()
{
    extern int SSB_net_initialized;
    int ret = 0;
    char recv_buf[SOCKET_RECV_BUF_LEN];
    char response_buf[256];
    ESP_LOGI(SSB_TAG, "Socket read thread start...\n");
    while (1)
    {
        vTaskDelay(100 / portTICK_PERIOD_MS);
        if (!SSB_net_initialized)
        {
            continue;
        }
        if (!socket_connected)
        {
            continue;
        }
        do
        {
            ret = recv(SSB_sockfd, recv_buf, SOCKET_RECV_BUF_LEN - 1, 0);
            if (ret <= 0)
            {
                break;
            }
            socket_not_received_count = 0;
            recv_buf[ret] = '\0';
            at_command_hand(recv_buf, 1);
            if (ssb_socket_cb != NULL)
            {
                ssb_socket_cb(recv_buf, ret + 1);
            }
            if (strstr(recv_buf, "OK:HB\r\n") == NULL)
            {
                sprintf(response_buf, BASE_SOCKET_RESPONSE, ret, -1);
                SSB_socket_write(response_buf, strlen(response_buf));
            }
        } while (1);
        SSB_socket_free();
    }
}

void SSB_init_socket(SSB_Socket_callback_fun cb,
                     SSB_on_socket_status_change_hand status_change_cb)
{
    ssb_socket_cb = cb;
    ssb_socket_status_change_cb = status_change_cb;

    xTaskCreate(SSB_socket_hearbeat_task,
                "SSB_socket_hearbeat_task",
                SOCKET_TASK_STACK_WORDS,
                NULL,
                SOCKET_TASK_PRIORITY,
                NULL);
    xTaskCreate(SSB_socket_read_task,
                "SSB_socket_read_task",
                SOCKET_TASK_STACK_WORDS / 2,
                NULL,
                SOCKET_TASK_PRIORITY,
                NULL);
}
